package pl.edu.pw.elka.jtrzasko.proz.warcaby.controller;

import pl.edu.pw.elka.jtrzasko.proz.warcaby.figures.FigureColor;
import pl.edu.pw.elka.jtrzasko.proz.warcaby.model.Model;
import pl.edu.pw.elka.jtrzasko.proz.warcaby.model.Position;

/**
 * Maszyna stanow odpowiadajaca za poprawne przeprowadzenie kazdego ruchu od poczatku do konca.
 */
public class MoveStateMachine
{
	/**
	 * Obecny stan ruchu
	 */
	private static MoveState State;
	/**
	 * Ostatnio klikniete pole na plaszy
	 */
	private static Position currentPosition;
	/**
	 * Czy kolejny ruch musi byc biciem.
	 */
	private static boolean isBeatingPosible;

	/**
	 * Stworzenie nowej maszyny stanow wraz z ustawieniem jej w stan podstawowy. 
	 */
	public MoveStateMachine()
	{
		State = MoveState.WAITING_FOR_FIRST_CLICK;
	}

	/**
	 * Pobiera obecny stan
	 * @return obecny stan
	 */
	public static MoveState getState()
	{
		return State;
	}

	/**
	 * Przechodzi do kolejnego stanu ruchu jesli spelnione sa odpowiednie warunki
	 * @param model Model, na ktorym sprawdzamy poprawnosc ruchu
	 * @param position Pozycja ostatniego klikniecia
	 * @param color Kolor gracza, ktory wykonuje ruch
	 */
	public void nextState(Model model, Position position, FigureColor color)
	{
		State.nextState(model, position, color);
	}

	/**
	 * Zwraca infomacje czy stan pozwala na zakonczenia ruchu.
	 * @return Prawda jesli stan jest stanem finalnym
	 */
	public boolean isFinalState()
	{
		return State.isFinalState();
	}
	
	/**
	 * Zwraca informacje czy ruch jest zakonczony
	 * @return Prawda jesli ruch jest zakonczony
	 */
	public boolean isMoveFinished()
	{
		if (State == MoveState.MOVE_FINISHED)
			return true;
		return false;
	}

	/**
	 * Poszczegolne stany ruchu na planszy
	 *
	 */
	private enum MoveState
	{

		/**
		 * Oczekiwanie na pierwsze klikniecie
		 */
		WAITING_FOR_FIRST_CLICK
		{

			boolean isFinalState()
			{
				return true;
			}

			void nextState(Model model, Position position, FigureColor color)
			{
				isBeatingPosible = false;
				if (model.isFieldEmpty(position))
					return;
				if (!model.isFigureColor(position, color))
					return;
				if (model.isBeatingPosible(color))
				{
					isBeatingPosible = true;
					if (!model.isBeatingValid(position))
						return;
				}
				currentPosition = position;
				State = WAITING_FOR_SECOND_CLICK;
			}
		},
		/**
		 * Oczekiwanie na drugie poprawne klikniecie
		 *
		 */
		WAITING_FOR_SECOND_CLICK
		{

			boolean isFinalState()
			{
				return true;
			}

			void nextState(Model model, Position position, FigureColor color)
			{
				if (isBeatingPosible)
					if (model.isFieldEmpty(position)
							&& model.isBeatingValid(currentPosition, position))
						State = MAKING_MOVE;
					else
					{
						State = WAITING_FOR_FIRST_CLICK;
						return;
					}
				else if (model.isFieldEmpty(position)
						&& model.isMoveValid(currentPosition, position))
					State = MAKING_MOVE;
				else
					State = WAITING_FOR_FIRST_CLICK;
			}
		},
		/**
		 * Wykonywanie przesuniecia figur na planszy
		 */
		MAKING_MOVE
		{

			boolean isFinalState()
			{
				return false;
			}

			void nextState(Model model, Position position, FigureColor color)
			{
				model.makeMove(currentPosition, position);
				currentPosition = position;
				if (isBeatingPosible && model.isBeatingValid(position))
				{
					isBeatingPosible = true;
					State = WAITING_FOR_NEXT_BEAT_CLICK;
				} else
					State = TESTING_PROMOTION;
			}
		},
		/**
		 * Sprawdzanie czy jest mozliwosc promocji
		 *
		 */
		TESTING_PROMOTION
		{

			boolean isFinalState()
			{
				return false;
			}

			void nextState(Model model, Position position, FigureColor color)
			{
				if (model.isPromotionValid(position))
					State = MAKING_PROMOTION;
				else
					State = MOVE_FINISHED;
			}
		},
		/**
		 * Dokonywanie promocji
		 *
		 */
		MAKING_PROMOTION
		{

			boolean isFinalState()
			{
				return false;
			}

			void nextState(Model model, Position position, FigureColor color)
			{
				model.makePromotion(position);
				State = MOVE_FINISHED;
			}
		},
		/**
		 * Oczekiwanie na kolejny ruch, ktory musi byc biciem
		 */
		WAITING_FOR_NEXT_BEAT_CLICK
		{

			boolean isFinalState()
			{
				return true;
			}

			void nextState(Model model, Position position, FigureColor color)
			{
				if (model.isFieldEmpty(position)
						&& model.isBeatingValid(currentPosition, position))
					State = MAKING_MOVE;

			}
		},
		/**
		 * Ruch zakonczony
		 */
		MOVE_FINISHED
		{

			boolean isFinalState()
			{
				return false;
			}

			void nextState(Model model, Position position, FigureColor color)
			{
				isBeatingPosible = false;
				State = WAITING_FOR_FIRST_CLICK;
			}
		};

		abstract boolean isFinalState();

		abstract void nextState(Model model, Position position,
				FigureColor color);

	}

}
